﻿using Microsoft.SharePoint;
using Microsoft.SharePoint.Taxonomy;
using System;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml;

namespace SPMetadataFilter.MetadataFilter
{
    public partial class MetadataFilterUserControl : UserControl
    {
        public string TermStoreGroup { get; set; }
        public string TermSet { get; set; }
        public string ColumnName { get; set; }
        public string StartingTermId { get; set; }

        public Microsoft.SharePoint.WebPartPages.SPWebPartManager WebPartManager { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(TermStoreGroup) || string.IsNullOrEmpty(TermSet) || string.IsNullOrEmpty(ColumnName))
                return;

            if (!Page.IsPostBack)
            {
                try
                {
                    TaxonomySession taxonomySession = new TaxonomySession(SPContext.Current.Site);
                    TermStore termStore = taxonomySession.TermStores[0];
                    Group group = termStore.Groups[this.TermStoreGroup];
                    TermSet termSet = group.TermSets[this.TermSet];
                    TreeNode root = null;
                    if (string.IsNullOrEmpty(this.StartingTermId))
                    {
                        root = new TreeNode(termSet.Name, string.Empty);
                        BuildNode(root, termSet.Terms);
                    }
                    else
                    {
                        Term rootTerm = termSet.GetTerm(new Guid(this.StartingTermId));
                        root = new TreeNode(rootTerm.Name, string.Empty);
                        BuildNode(root, rootTerm.Terms);
                    }
                    root.Expand();
                    tvTerms.Nodes.Add(root);
                }
                catch
                {
                    //Todo: error handling 
                }
            }
            else
            {
                if (!string.IsNullOrEmpty(tvTerms.SelectedValue))
                    filterWebparts();
            }
        }

        private void BuildNode(TreeNode parent, TermCollection terms)
        {
            foreach (Term term in terms)
            {
                TreeNode node = new TreeNode(term.Name, term.Id.ToString());
                node.Collapse();
                BuildNode(node, term.Terms);
                parent.ChildNodes.Add(node);
            }
        }




        protected void tvTerms_SelectedNodeChanged(object sender, EventArgs e)
        {
            tvTerms.SelectedNode.Expand();

            ////tvTerms.SelectedNode.NavigateUrl = "javascript:void(0)";
            filterWebparts();
        }

        private void filterWebparts()
        {
            if (WebPartManager != null)
            {
                foreach (WebPart webPart in WebPartManager.WebParts)
                {
                    if (webPart != null && (webPart is Microsoft.SharePoint.WebPartPages.ListViewWebPart || webPart is Microsoft.SharePoint.WebPartPages.XsltListViewWebPart))
                    {
                        Microsoft.SharePoint.WebPartPages.XsltListViewWebPart xlvwpFilterablePart = webPart as Microsoft.SharePoint.WebPartPages.XsltListViewWebPart;

                        SPList list = SPContext.Current.Web.Lists[xlvwpFilterablePart.ListId];
                        if (list.Fields.ContainsFieldWithStaticName(this.ColumnName))
                        {
                            string originalQuery = GetInnerXmlFromXmlString("View/Query", xlvwpFilterablePart.XmlDefinition);

                            //TODO: improve the caml query
                            xlvwpFilterablePart.XmlDefinition = SetInnerXmlForViewXmlString("View/Query", AddSubOrgsFilterToQuery(originalQuery), xlvwpFilterablePart.XmlDefinition);
                        }
                    }
                }

            }
        }

        private string AddSubOrgsFilterToQuery(string originalQuery)
        {
            TaxonomySession taxonomySession = new TaxonomySession(SPContext.Current.Site);
            TermStore termStore = taxonomySession.TermStores[0];
            Group group = termStore.Groups[this.TermStoreGroup];
            TermSet termSet = group.TermSets[this.TermSet];

            //BUILD new "Where" element
            int[] ids = new int[] { };
            if (!string.IsNullOrEmpty(tvTerms.SelectedValue))
                ids = TaxonomyField.GetWssIdsOfTerm(SPContext.Current.Site, termStore.Id, termSet.Id, new Guid(tvTerms.SelectedValue), true, 100);

            StringBuilder sb = new StringBuilder();

            sb.Append("<In><FieldRef LookupId='TRUE' Name='");
            sb.Append(this.ColumnName);
            sb.Append("' /><Values>");

            if (ids.Length > 0)
            {
                foreach (int i in ids)
                {
                    sb.Append("<Value Type='Integer'>");
                    sb.Append(i.ToString());
                    sb.Append("</Value>");
                }
            }
            else if (!string.IsNullOrEmpty(tvTerms.SelectedValue))
                sb.Append("<Value Type='Integer'>-1</Value>");

            sb.Append("</Values></In>");

            XmlDocument doc = new XmlDocument();
            doc.LoadXml("<Query>" + originalQuery + "</Query>");
            XmlNode node = doc.SelectSingleNode("Where");
            if (node == null)
                node = doc.CreateNode(XmlNodeType.Element, "Where", "");

            node.InnerXml = sb.ToString();

            doc.FirstChild.PrependChild(node);
            return doc.FirstChild.InnerXml;
        }

        private string GetInnerXmlFromXmlString(string xmlTag, string xmlDefinition)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xmlDefinition);
            XmlNode node = doc.SelectSingleNode(xmlTag);
            return node.InnerXml;
        }
        private string SetInnerXmlForViewXmlString(string xmlTag, string value, string xmlDefinition)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xmlDefinition);
            XmlNode node = doc.SelectSingleNode(xmlTag);
            node.InnerXml = value;
            if (string.IsNullOrEmpty(tvTerms.SelectedValue))
            {
                XmlNode Where = doc.SelectSingleNode(xmlTag + "/Where");
                if (Where != null)
                    Where.ParentNode.RemoveChild(Where);
                //node.InnerXml = "<OrderBy><FieldRef Name='ID'/></OrderBy>";
            }

            return doc.InnerXml;
        }
    }
}
